﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Xml;
using System.ServiceModel.Syndication; // for SyndicationFeed
using System.IO;

using MASAS.Common.Geometry;
using MASAS.MSM.DomainLayer.Logging;
using MASAS.MSM.DomainLayer.Model;

namespace MASAS.MSM.DomainLayer
{

    /// <summary>
    /// MASAS Facade class.
    /// </summary>
    /// <remarks>
    /// Facade pattern that connects to a MASAS Hub and abstracts away key details.
    /// </remarks>
    public class HubFacade
    {

        /// <summary>
        /// Gets the entries.
        /// </summary>
        /// <returns></returns>
        public List<HubEntry> GetEntries( Hub hub )
        {
            DateTime accessTime = DateTime.UtcNow;
            string feedXml = string.Empty; 
            List<HubEntry> entryList = new List<HubEntry>();

            string dtSince = string.Empty;
            if( hub.LastPolled.Ticks > 0 ) {
                dtSince = "dtsince=" + XmlConvert.ToString( hub.LastPolled.ToUniversalTime(), "yyyy-MM-ddTHH:mm:ssZ" );
            }

            string requestUri = hub.URI + "/feed";
            if( dtSince != string.Empty )
            {
                requestUri += "?" + dtSince;
            }
            
            WebClient webClient = new WebClient();
            webClient.Encoding = Encoding.UTF8;
            webClient.Headers.Add( "Authorization", "MASAS-Secret " + hub.Token );

            try
            {
                Logger.AddLogEntry( "Hub Request: " + requestUri );
                feedXml = webClient.DownloadString( requestUri );
            }
            catch( WebException webEx )
            {
                Logger.AddLogEntry( "Error - Could not retrieve the feed from hub (" + requestUri + ").", webEx );
            }
            catch( Exception ex )
            {
                Logger.AddLogEntry( "Error - Could not retrieve the feed from hub (" + requestUri + ").", ex );
            }

            if( feedXml != string.Empty )
            {
                StringReader strReader = new StringReader( feedXml );
                XmlReader xmlReader = XmlReader.Create( strReader );
                SyndicationFeed feed = SyndicationFeed.Load( xmlReader );
                xmlReader.Close();
                strReader.Close();

                hub.LastPolled = feed.LastUpdatedTime.DateTime;

                Logger.AddLogEntry( feed.Id );

                if( feed.Items.Count() > 0 )
                {
                    Logger.AddLogEntry( feed.Items.Count().ToString() + " new items have been retrieved." );
                    foreach( SyndicationItem entry in feed.Items )
                    {
                        // Create then Hub Entry from the feed item...
                        HubEntry hubEntry = HubEntry.Create( entry );

                        // need to store the RAW XML of the entry itself, therefore retrieve the XML directly into an XMLDoc
                        foreach( SyndicationLink link in entry.Links )
                        {
                            if( ( link.RelationshipType == "enclosure" ) && ( link.MediaType == "application/common-alerting-protocol+xml" ) )
                            {
                                // we have a CAP enclosure.
                                try {
                                    hubEntry.AlertXML = webClient.DownloadString( link.Uri );
                                }
                                catch( WebException webEx )
                                {
                                    Logger.AddLogEntry( "Error - Could not retrieve the linked item from hub (" + link.Uri + ").", webEx );
                                }
                                catch( Exception ex )
                                {
                                    Logger.AddLogEntry( "Error - Could not retrieve the linked item from hub (" + link.Uri + ").", ex );
                                }
                            }
                        }

                        entryList.Add( hubEntry );
                    }
                }
            }

            webClient.Dispose();

            // Everything is good, update the last access time.
            hub.LastPolled = accessTime;

            return entryList;
        }

        /// <summary>
        /// Gets the entries found within the given bounding box.
        /// </summary>
        /// <param name="boundingBox">The bounding box.</param>
        /// <returns></returns>
        public HubEntry[] GetEntries( GeoEnvelope boundingBox )
        {
            // TODO - Implement this.
            throw new System.NotImplementedException();
        }

        /// <summary>
        /// Gets the entries found in the given area.
        /// </summary>
        /// <param name="centerPoint">The center point.</param>
        /// <param name="radius">The radius.</param>
        /// <returns></returns>
        public HubEntry[] GetEntries( GeoPoint centerPoint, Int32 radius )
        {
            // TODO - Implement this.
            throw new System.NotImplementedException();
        }

        /// <summary>
        /// Adds the entry.
        /// </summary>
        public void AddEntry()
        {
            // TODO - Implement this.
            throw new System.NotImplementedException();
        }

        /// <summary>
        /// Updates the entry.
        /// </summary>
        public void UpdateEntry()
        {
            // TODO - Implement this.
            throw new System.NotImplementedException();
        }

        /// <summary>
        /// Cancels the entry.
        /// </summary>
        public void CancelEntry()
        {
            // TODO - Implement this.
            throw new System.NotImplementedException();
        }

        /// <summary>
        /// Gets the revisions for entry.
        /// </summary>
        /// <returns></returns>
        public HubEntry[] GetRevisionsForEntry()
        {
            // TODO - Implement this.
            throw new System.NotImplementedException();
        }

        /// <summary>
        /// Retrieves a document (TYPE??) from MASAS.
        /// </summary>
        public void GetDocument()
        {
            // TODO - Implement this.
            throw new System.NotImplementedException();
        }

        /// <summary>
        /// NEED: document definition (MIME type + bin?)
        /// </summary>
        public void UploadDocument()
        {
            // TODO - Implement this.
            throw new System.NotImplementedException();
        }

    }

}